package com.dh.spring.thread;

import com.dh.spring.util.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * 线程池阻塞队列接口实现类
 * */
public class CustomDefaultTaskBlockQueue implements CustomTaskBlockQueue {
    private static final Logger logger = LoggerFactory.getLogger(CustomTaskBlockQueue.class);
    //TODO 任务队列限制大小
    private int limit = 1000;
    //TODO 任务阻塞队列
    private static LinkedList<Runnable> linkedRunnableList = new LinkedList<>(); //TODO Runnable任务阻塞队列
    private static LinkedList<FutureTask<Callable>> linkedCallableList = new LinkedList<>(); //TODO Callable任务阻塞队列
    private static volatile Object runnableObj = new Object(), callableObj = new Object();
    private static volatile CustomTaskBlockQueue customTaskBlockQueue = null;

    private CustomDefaultTaskBlockQueue(int limit) {
        this.limit = limit;
    }

    public static CustomTaskBlockQueue getInstance() {
        if(null == customTaskBlockQueue) {
            synchronized (CustomDefaultTaskBlockQueue.class) {
                if(null == customTaskBlockQueue) {
                    customTaskBlockQueue = new CustomDefaultTaskBlockQueue(1000);
                }
            }
        }

        return customTaskBlockQueue;
    }

    @Override
    public void offerRunnable(Runnable runnable, CustomThreadPool customThreadPool, CustomAbortPolicy customAbortPolicy) {
        if(null != runnable) {
            //TODO 并发情况下提交任务需要同步
            synchronized (runnableObj) {
                //TODO 任务阻塞队列任务数小于最大任务数，则添加任务
                if (this.getRunnableTaskBlockQueueSize() < this.limit) {
                    linkedRunnableList.add(runnable);
                    logger.info("[ " + LocalTime.formatDate(LocalDateTime.now())
                        + " 当前线程 [ " + Thread.currentThread().getName() + " ] 获取到this.linkedRunnableList同步锁，并向CustomDefaultTaskBlockQueue队列添加任务成功，当前队列任务个数为：taskBlockQueueSize = " + this.getRunnableTaskBlockQueueSize() + "");
                    //TODO 唤醒所有阻塞在linkedList对象上的线程，用于从此对象上获取任务
                    runnableObj.notify();
                } else {
                    try {
                        customAbortPolicy.reject(runnable, customThreadPool);
                    } catch (Exception e) {
                        logger.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " 当前任务阻塞队列提交任务失败，原因为：[ " + e.getMessage() + " ]......");
                    }
                }
            }
        }
    }

    @Override
    public boolean offerCallable(FutureTask<Callable> futureTask, CustomThreadPool customThreadPool, CustomAbortPolicy customAbortPolicy) {
        boolean status = false;
        if(null != futureTask) {
            //TODO 并发情况下提交任务需要同步
            synchronized (callableObj) {
                //TODO 任务阻塞队列任务数小于最大任务数，则添加任务
                if (this.getCallableTaskBlockQueueSize() < this.limit) {
                    status = linkedCallableList.add(futureTask);
                    logger.info("[ " + LocalTime.formatDate(LocalDateTime.now())
                        + " 当前线程 [ " + Thread.currentThread().getName() + " ] 获取到this.linkedCallableList同步锁，当前队列任务个数为：taskBlockQueueSize = " + this.getCallableTaskBlockQueueSize() + "");
                    //TODO 唤醒所有阻塞在linkedList对象上的线程，用于从此对象上获取任务
                    callableObj.notify();
                } else {
                    try {
                        customAbortPolicy.reject(futureTask, customThreadPool);
                    } catch (Exception e) {
                        logger.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " 当前任务阻塞队列提交任务失败，原因为：[ " + e.getMessage() + " ]......");
                    }
                }
            }
        }

        return status;
    }

    @Override
    public Runnable takeRunnable() {
        Runnable runnable = null;
        synchronized (runnableObj) {
            while (linkedRunnableList.isEmpty()) {
                try {
                    logger.info("[ " + LocalTime.formatDate(LocalDateTime.now())
                        + " 当前任务阻塞队列任务为空，线程 [ " + Thread.currentThread().getName() + " ] 进入等待任务就绪......");

                    //TODO 如果任务队列为空，线程将执行任务队列的wait()方法执行阻塞
                    runnableObj.wait(0);
                    logger.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " 当前任务阻塞队列有新任务，线程 [ " + Thread.currentThread().getName() + " ] 被唤醒开始执行任务......");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            try {
                //TODO 捕获抛出的NoSuchElementException，保证线程可用，不中断
                if(!linkedRunnableList.isEmpty()) {
                    runnable = linkedRunnableList.poll();
                    logger.info(LocalTime.formatDate(LocalDateTime.now()) + " CustomDefaultTaskBlockQueue队列取出任务成功，当前队列任务个数为：taskBlockQueueSize = " + this.getRunnableTaskBlockQueueSize());
                }
            } catch (NoSuchElementException e) {
                logger.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ]" + " 当前线程 thread = " + Thread.currentThread().getName() + "在获取任务过程中出现NoSuchElementException异常，异常为：" + e.getMessage());
            }

        }

        return runnable;
    }

    @Override
    public FutureTask<Callable> takeCallable() {
        FutureTask<Callable> futureTask = null;
        synchronized (callableObj) {
            while (linkedCallableList.isEmpty()) {
                try {
                    logger.info("[ " + LocalTime.formatDate(LocalDateTime.now())
                        + " 当前任务阻塞队列任务为空，线程 [ " + Thread.currentThread().getName() + " ] 进入等待任务就绪......");

                    //TODO 如果任务队列为空，线程将执行任务队列的wait()方法执行阻塞
                    callableObj.wait(0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            try {
                //TODO 捕获抛出的NoSuchElementException，保证线程可用，不中断
                if(!linkedCallableList.isEmpty()) {
                    futureTask = linkedCallableList.poll();
                    logger.info(LocalTime.formatDate(LocalDateTime.now()) + " CustomDefaultTaskBlockQueue队列取出任务成功，当前队列任务个数为：taskBlockQueueSize = " + this.getCallableTaskBlockQueueSize());
                }
            } catch (NoSuchElementException e) {
                logger.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ]" + " 当前线程 thread = " + Thread.currentThread().getName() + "在获取任务过程中出现NoSuchElementException异常，异常为：" + e.getMessage());
            }

        }

        return futureTask;
    }

    @Override
    public boolean getRunnableTaskBlockQueueIsEmpty() {
        return linkedRunnableList.isEmpty();
    }

    @Override
    public boolean getCallableTaskBlockQueueIsEmpty() {
        return linkedCallableList.isEmpty();
    }

    @Override
    public int getRunnableTaskBlockQueueSize() {
        return linkedRunnableList.size();
    }

    @Override
    public int getCallableTaskBlockQueueSize() {
        return linkedCallableList.size();
    }
}
